package org.yzbdl.lanius.core.plugins.unInstall;

import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ObjectUtil;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.plugins.Plugin;
import org.pentaho.di.core.plugins.PluginInterface;
import org.pentaho.di.core.plugins.PluginRegistry;
import org.pentaho.di.core.util.StringUtil;
import org.yzbdl.lanius.core.constant.LocalDir;
import org.yzbdl.lanius.core.event.EventContext;
import org.yzbdl.lanius.core.exception.LaniusEngineDbException;
import org.yzbdl.lanius.core.plugins.ClassLoaderManager;
import org.yzbdl.lanius.core.plugins.event.PluginDeleteEvent;
import org.yzbdl.lanius.core.plugins.metastore.LdrPluginDao;
import org.yzbdl.lanius.core.plugins.metastore.LdrPluginEntity;

import javax.transaction.Transactional;
import java.io.File;
import java.util.*;

public class PluginUninstaller {

    private final String SPACE_CHAR = " ";

    private LdrPluginDao ldrPluginDao = LdrPluginDao.getInstance();

    private static PluginUninstaller pluginUninstaller;

    public PluginUninstaller() {
    }

    public static PluginUninstaller getInstance() {
        if (ObjectUtil.isEmpty(PluginUninstaller.pluginUninstaller)) {
            PluginUninstaller.pluginUninstaller = new PluginUninstaller();
        }
        return PluginUninstaller.pluginUninstaller;
    }

    public Boolean uninstallAll() throws LaniusEngineDbException {
        List<LdrPluginEntity> entityList = ldrPluginDao.getAll();
        for (LdrPluginEntity ldrPluginEntity : entityList) {
            Boolean aBoolean = uninstallPlugin(ldrPluginEntity.getPluginId(), ldrPluginEntity.getPluginTypeName(), ldrPluginEntity.getVersion());
        }
        return true;
    }

    @Transactional
    public Boolean uninstallPlugin(String id, String pluginTypeClass, String version) {
        try {
//		从数据库获取插件信息
            LdrPluginEntity entity = ldrPluginDao.getLocalVersionOne(id, pluginTypeClass, version);
//		获取插件
            Plugin plugin = Plugin.from(entity);
//            从注册中心移除插件
            PluginRegistry registry = PluginRegistry.getInstance();
            PluginInterface pluginWithId = registry.getPlugin(entity.getPluginTypeClass(), entity.getPluginId(), entity.getVersion());
            if (ObjectUtil.isNotEmpty(pluginWithId)) {
                registry.removePlugin(entity.getPluginTypeClass(), pluginWithId);
            }
//		获取插件的类加载器
            ClassLoaderManager.getInstance().removeClassLoader(plugin);

//            PluginRegistry registry = PluginRegistry.getInstance();
//            PluginInterface pluginWithId = registry.getPlugin(entity.getPluginTypeClass(), entity.getPluginId(), entity.getVersion());
//            registry.removePlugin(entity.getPluginTypeClass(),pluginWithId);

//		获取插件依赖jar,进行删除文件
            String[] libraryArray = entity.getLibraryArray();
            if (ArrayUtils.isNotEmpty(libraryArray) && !(libraryArray.length == 1 && StringUtil.isEmpty(libraryArray[0]))) {
                File libPlugin = new File(LocalDir.LIB_PLUGINS);
                if (!libPlugin.exists()) {
                    throw new KettleException("插件依赖目录不存在");
                }
                if (ArrayUtils.isEmpty(libPlugin.listFiles())) {
                    throw new KettleException("插件依赖目录下为空");
                }
                List<File> files = Arrays.asList(libPlugin.listFiles());
                List<File> list = findJar(files, Arrays.asList(libraryArray));
                list.forEach(item -> {
                    boolean delete = item.delete();
                    if (!delete) {
                        Console.error("删除文件" + item.getName() + "失败");
                    }
                });
            }

            if (plugin != null) {
//                删除插件本地文件
                File file = new File(plugin.getPluginDirectoryString());

//                boolean delete = FileUtil.del(file);

                boolean delete = PluginUninstaller.DeleteFolder(file);
                if (!delete) {
                    Console.log("删除文件" + file.getName() + "失败");
                    throw new KettleException("删除文件" + file.getName() + "失败");
                }
                ldrPluginDao.delete(entity.getId());
                EventContext.publish(new PluginDeleteEvent(entity));
            } else {
                ldrPluginDao.delete(entity.getId());
                EventContext.publish(new PluginDeleteEvent(entity));
            }
            return true;
        } catch (KettleException e) {
            Console.error("卸载插件失败");
            e.printStackTrace();
            return false;
        }
    }

    private List<File> findJar(List<File> files, List<String> jars) {
        files.sort((File o1, File o2) -> o1.getName().compareTo(o2.getName()));
        Collections.sort(jars);
        ArrayList<File> returnList = new ArrayList<>();
        char flag = 0;
        for (int i = 0; i < jars.size(); i++) {
            a:
            {
                for (File file : files) {
//				判断是否存在标记,是否满足标记
                    if (flag != 0) {
                        if (file.getName().charAt(0) < flag) {
                            continue;
                        }
                    }
//				判断是以什么开头
                    if (StringUtil.isEmpty(jars.get(i))) {
                        continue;
                    }
                    if (file.getName().charAt(0) < jars.get(i).charAt(0)) {
                        continue;
                    }
//				判断是否是该对象 是跳到下一个目标
                    if (file.getName().equals(jars.get(i))) {
                        returnList.add(file);
                        flag = jars.get(i).charAt(0);
                        break a;
                    }
                }
            }
        }
        return returnList;
    }

    public static boolean DeleteFolder(File file) {
        boolean flag = false;
        // 判断目录或文件是否存在 // 不存在返回 false
        if (!file.exists()) {
            return flag;
        } else {
            // 判断是否为文件  // 为文件时调用删除文件方法
            if (file.isFile()) {
                return PluginUninstaller.deleteFile(file);
            } else {  // 为目录时调用删除目录方法
                return PluginUninstaller.deleteDirectory(file);
            }
        }
    }


    public static boolean deleteFile(File file) {
        boolean flag = false;
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            boolean delete = file.delete();
            Console.log("提示：" + file.getName() + "删除" + (delete ? "成功" : "失败"));
            flag = true;
        }
        return flag;
    }

    /**
     * 删除目录以及目录下的文件
     *
     * @param dirFile 被删除目录的路径
     * @return 目录删除成功返回true，否则返回false
     */
    public static boolean deleteDirectory(File dirFile) {
        //如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        //删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            //删除子文件
            if (files[i].isFile()) {
                flag = PluginUninstaller.deleteFile(new File(files[i].getAbsolutePath()));
                if (!flag) {
                    break;
                }
            } //删除子目录
            else {
                flag = PluginUninstaller.deleteDirectory(new File(files[i].getAbsolutePath()));
                if (!flag) {
                    break;
                }
            }
        }
        if (!flag) {
            return false;
        }
        //删除当前目录
        if (dirFile.delete()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 插件卸载逻辑
     */
    public void uninstall() {
        Console.print("请输入：");
        Scanner scanner = new Scanner(System.in);
        String inputStr = scanner.nextLine().trim();
        switch (inputStr.toLowerCase()) {
            case "ALL":
                try {
                    uninstallAll();
                    Console.log("所有插件已成功卸载。");
                } catch (LaniusEngineDbException e) {
                    uninstall();
                }
                break;
            case "quit":
                Console.log("退出成功。");
                System.exit(0);
        }
        try {
            if (StringUtils.isBlank(inputStr)) {
                Console.log("输入有误，请按-h示例填写。");
                uninstall();
            }
            String[] unInstallPluginArr = new String[]{inputStr};
            if (inputStr.contains(SPACE_CHAR)) {
                unInstallPluginArr = inputStr.split(SPACE_CHAR);
            }

            for (String str : unInstallPluginArr) {
                String pluId = str.split(":")[0];
                String pluVer = str.split(":")[1];
                LdrPluginEntity ldrPluginEntity = ldrPluginDao.findByPluginIdIgnoreCaseWithVersion(pluId, pluVer);
                if (ObjectUtil.isEmpty(ldrPluginEntity)) {
                    Console.log("无法找到插件:" + str);
                    continue;
                }
                uninstallPlugin(ldrPluginEntity.getPluginId(), ldrPluginEntity.getPluginTypeName(), ldrPluginEntity.getVersion());
                Console.log("插件:" + str + "卸载成功。");
            }
            uninstall();
        } catch (Exception e) {
            Console.log("无法卸载指定插件。");
            System.exit(0);
        }
    }
}